<?php

class Tree {

    public function __construct() {
        
    }

    /**
     * <code>
     * $key_files = array(
     *    "/etc/php5" => "/etc/php5",
     *    "/etc/php5/cli" => "/etc/php5/cli",
     *    "/etc/php5/cli/conf.d" => "/etc/php5/cli/conf.d",
     *    "/etc/php5/cli/php.ini" => "/etc/php5/cli/php.ini",
     *    "/etc/php5/conf.d" => "/etc/php5/conf.d",
     *    "/etc/php5/conf.d/mysqli.ini" => "/etc/php5/conf.d/mysqli.ini",
     *    "/etc/php5/conf.d/curl.ini" => "/etc/php5/conf.d/curl.ini",
     * );
     *
     * $tree = explodeTree($key_files, "/", true);
     *
     * print_r($tree);
     *
     * // Array
     * // (
     * //     [etc] => Array
     * //         (
     * //             [php5] => Array
     * //                 (
     * //                     [__base_val] => /etc/php5
     * //                     [cli] => Array
     * //                         (
     * //                             [__base_val] => /etc/php5/cli
     * //                             [conf.d] => /etc/php5/cli/conf.d
     * //                             [php.ini] => /etc/php5/cli/php.ini
     * //                         )
     * //                     [conf.d] => Array
     * //                         (
     * //                             [__base_val] => /etc/php5/conf.d
     * //                             [mysqli.ini] => /etc/php5/conf.d/mysqli.ini
     * //                             [curl.ini] => /etc/php5/conf.d/curl.ini
     * //                         )
     * //                 )
     * //         )
     * // )
     * </code>
     *
     * @param array   $array
     * @param string  $delimiter
     * @param boolean $baseval
     *
     * @return array
     */
    public function explodeTree($array, $delimiter = '.', $baseval = false) {
        if (!is_array($array)) {
            return false;
        }
        $splitRE = '/' . preg_quote($delimiter, '/') . '/';
        $returnArr = array();
        foreach ($array as $key => $val) {
            $parts = preg_split($splitRE, $key, -1, PREG_SPLIT_NO_EMPTY);
            $leafPart = array_pop($parts);

            $parentArr = &$returnArr;
            foreach ($parts as $part) {
                if (!isset($parentArr[$part])) {
                    $parentArr[$part] = array();
                } else if (!is_array($parentArr[$part])) {
                    if ($baseval) {
                        $parentArr[$part] = array('__base_val' => $parentArr[$part]);
                    } else {
                        $parentArr[$part] = array();
                    }
                }
                $parentArr = &$parentArr[$part];
            }

            if (empty($parentArr[$leafPart])) {
                $parentArr[$leafPart] = $val;
            } else if ($baseval && is_array($parentArr[$leafPart])) {
                $parentArr[$leafPart]['__base_val'] = $val;
            }
        }
        return $returnArr;
    }

    public function plotTree($arr, $indent=0) {
        $treeHtml = '';
        foreach ($arr as $k=>$v){
            if ($k == '__base_val') {
                continue;
            }
            $show_val = (is_array($v) ? (isset($v['__base_val'])) ? $v['__base_val'] : '' : $v);
            $treeHtml .= str_repeat("  ", $indent);
            if ($indent == 0) {
                $treeHtml .= 'O ';
            } else if (is_array($v)) {
                $treeHtml .= '+ ';
            } else {
                $treeHtml .= '- ';
            }
            
            if (is_array($v)) {
                $treeHtml .= $k . " (input) " . "\n";
                $treeHtml .= $this->plotTree($v, ($indent+1));
            } else {
                $treeHtml .= $k . " $show_val " . "\n";
            }
        }
        return $treeHtml;
    }

    /**
     * <code>
     * $settings = array(
     *    "Credits" => "@appname@ created by @author@",
     *    "Description" => "@appname@ can parse logfiles and store then in mysql",
     *    "@author@_mail" => "bin.zhao@pactera.com"
     * );
     * $mapping = array(
     *    "@author@" => "zb",
     *    "@appname@" => "logchopper"
     * );
     *
     * $settings = replaceTree(array_keys($mapping), array_values($mapping), $settings, true);
     *
     * print_r($settings);
     *
     * // Array
     * // (
     * //     [Credits] => logchopper created by zb
     * //     [Description] => logchopper can parse logfiles and store then in mysql
     * //     [kevin_mail] => bin.zhao@pactera.com
     * // )
     * </code>
     *
     * @param string  $search
     * @param string  $replace
     * @param array   $array
     * @param boolean $keys_too
     *
     * @return array
     */
    public function replaceTree($search = "", $replace = "", $array = false, $keys_too = false) {
        if (!is_array($array)) {
            return str_replace($search, $replace, $array);
        }
        $newArr = array();
        foreach ($array as $k => $v) {
            $add_key = $k;
            if ($keys_too) {
                $add_key = str_replace($search, $replace, $k);
            }
            $newArr[$add_key] = $this->replaceTree($search, $replace, $v, $keys_too);
        }
        return $newArr;
    }

    /**
     * <code>
     * // Input //
     * $array = array(
     *    "c" => array(
     *        "d" => 4,
     *        "a" => 1,
     *        "b" => 2,
     *        "c" => 3,
     *        "e" => 5
     *    ),
     *    "a" => array(
     *        "d" => 4,
     *        "b" => 2,
     *        "a" => 1,
     *        "e" => 5,
     *        "c" => 3
     *    ),
     *    "b" => array(
     *        "d" => 4,
     *        "b" => 2,
     *        "c" => 3,
     *        "a" => 1
     *    )
     * );
     *
     * ksortTree($array);
     *
     * print_r($array);
     *
     * // Array
     * // (
     * //     [a] => Array
     * //         (
     * //             [a] => 1
     * //             [b] => 2
     * //             [c] => 3
     * //             [d] => 4
     * //             [e] => 5
     * //         )
     * //
     * //     [b] => Array
     * //         (
     * //             [a] => 1
     * //             [b] => 2
     * //             [c] => 3
     * //             [d] => 4
     * //         )
     * //
     * //     [c] => Array
     * //         (
     * //             [a] => 1
     * //             [b] => 2
     * //             [c] => 3
     * //             [d] => 4
     * //             [e] => 5
     * //         )
     * //
     * // )
     * </code>
     *
     * @param array $array
     */
    function ksortTree(&$array, $sortBy = 'k') {
        if (!is_array($array)) {
            return false;
        }
        if ($sortBy == 'k') {
            ksort($array);
        } else {
            sort($array);
        }
        foreach ($array as $k => $v) {
            $this->ksortTree($array[$k], $sortBy);
        }
        return true;
    }



}
